﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using BVCommon.Entities;
using BVClient.ProductServiceReference;
using System.ComponentModel;
using System.Collections.ObjectModel;

namespace BVClient.Managers
{
    public class ProductProvider
    {
        private IList<Product> products;
        private ObservableCollection<BVProduct> bvProducts = new ObservableCollection<BVProduct>();
        private bool isLoaded = false;

        public ObservableCollection<BVProduct> GetProducts()
        {
            if (!isLoaded)
            {
                loadData();
            }
            return bvProducts; 
        }

        public ObservableCollection<string> GetMeasurementList()
        {
            ObservableCollection<string> list = new ObservableCollection<string>();

            var dataList = (from g in bvProducts 
                            select g.Measurement).Distinct();

            foreach (string item in dataList)
            {
                list.Add(item);
            }
            return list;
        }

        public ProductProvider() 
        {}

        private void loadData()
        {
            using (ProductServiceClient client = new ProductServiceClient())
            {
                products = client.GetData().ToList();
            }
            foreach (Product item in products)
            {
                bvProducts.Add(new BVProduct(item));
            }
            isLoaded = true;
        }

        public void SaveData()
        {
            using (ProductServiceClient client = new ProductServiceClient())
            {
                IList<Product> list = new List<Product>();
                foreach (BVProduct item in bvProducts)
                {
                    list.Add(ConvertToDbObject(item));
                }
                client.SaveData(list.ToArray());
            }
            products.Clear();
            bvProducts.Clear();
            loadData();
        }

        private Product ConvertToDbObject(BVProduct sourceItem)
        {
            IEnumerable<Product> dbProducts = (from p in products
                                               where p.id == sourceItem.Id
                                               select p);
            if (dbProducts.Count() == 0)
            {
                return new Product()
                {
                    name = sourceItem.Name,
                    code = sourceItem.Code,
                    cost = sourceItem.Cost,
                    measurement = sourceItem.Measurement,
                    available_quantity = sourceItem.Quantity
                };
            }
            else if (dbProducts.Count() == 1)
            {
                dbProducts.ElementAt(0).name = sourceItem.Name;
                dbProducts.ElementAt(0).code = sourceItem.Code;
                dbProducts.ElementAt(0).measurement = sourceItem.Measurement;
                dbProducts.ElementAt(0).cost = sourceItem.Cost;
                dbProducts.ElementAt(0).available_quantity = sourceItem.Quantity;

                return dbProducts.ElementAt(0);
            }
            else
            {
                throw new ArgumentException("Two or more items have equal isentifier");
            }
        }
    }

    public class BVProduct : IDataErrorInfo
    {
        //private readonly Regex nameEx = new Regex(@"^[A-Za-z ]+$");

        public Int32 Id
        { get; set; }

        public string Name
        { get; set; }

        public string Code
        { get; set; }

        public string Measurement
        { get; set; }

        public decimal Cost
        { get; set; }

        public decimal Quantity
        { get; set; }

        public BVProduct() { }

        public BVProduct(Product product)
        {
            Id = product.id;
            UpdateItem(product);
        }

        public void UpdateItem(Product product)
        {
            Name = product.name;
            Code = product.code;
            Measurement = product.measurement;
            Cost = (product.cost ?? 0);
            Quantity = (product.available_quantity ?? 0);
        }

        #region IDataErrorInfo Members

        public string Error
        {
            get
            {
                StringBuilder error = new StringBuilder();
                // iterate over all of the properties
                // of this object - aggregating any validation errors
                PropertyDescriptorCollection props = TypeDescriptor.GetProperties(this);
                foreach (PropertyDescriptor prop in props)
                {
                    string propertyError = this[prop.Name];
                    if (propertyError != string.Empty)
                    {
                        error.Append((error.Length!=0  ? ", " : "") + propertyError);
                    }
                }
                return error.ToString();
            }
        }

        public string this[string columnName]
        {
            get
            {
                // apply property level validation rules
                if (columnName.Equals("Name") && String.IsNullOrEmpty(Name))
                {
                    return "Name cannot be null or empty";
                }
                if (columnName.Equals("Code") && String.IsNullOrEmpty(Code))
                {
                    return "Code cannot be null or empty";
                }
                if (columnName.Equals("Cost") && Cost < 0)
                {
                    return "Cost cannot be a negative number";
                }
                if (columnName.Equals("Quantity") && Quantity < 0)
                {
                    return "Quantity cannot be a negative number";
                }
                return String.Empty;
            }
        }

        #endregion
    }
}
